package com.dc.java8._7_optional;

import cn.hutool.core.util.StrUtil;
import com.dc.java8._1_lambda.Person;
import lombok.Data;
import org.junit.Test;

import java.util.Objects;
import java.util.Optional;

/**
 * Optional 容器类：用于尽量避免空指针异常
 *
 * 	Optional.of(T t) : 创建一个 Optional 实例,,参数为空时，会抛出异常
 * 	Optional.empty() : 创建一个空的 Optional 实例
 * 	Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
 * 	isPresent() : 判断是否包含值
 * 	orElse(T t) :  如果调用对象包含值，返回该值，否则返回t
 * 	orElseGet(Supplier s) :如果调用对象包含值，返回该值，否则返回 s 获取的值
 * 	map(Function f): 如果有值对其处理，并返回处理后的Optional，否则返回 Optional.empty()
 * 	flatMap(Function mapper):与 map 类似，要求返回值必须是Optional
 */
public class OptionalTest {

	/**
	 * Optional.of(T t) : 创建一个 Optional 实例,,参数为空时，会抛出异常
	 * Optional.empty() : 创建一个空的 Optional 实例
	 * Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
	 */
	@Test
	public void test1() {
		Optional<Person> op = Optional.of(new Person());
		//Optional<Person> op = Optional.of(null);
		System.out.println(op.get());

		// 创建一个空的 Optional 实例，数据为空时，获取会报错
		//Optional<Person> op2 = Optional.empty();
		//System.out.println(op2.get());

		// Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
		Optional<Person> op3 = Optional.ofNullable(new Person());
		System.out.println(op3.get());
	}

	/**
	 * isPresent() : 判断是否包含值
	 */
	@Test
	public void test2() {
		Optional<Person> op = Optional.ofNullable(new Person());
		if (op.isPresent()) {
			System.out.println(op.get());
		}
	}

	/**
	 * orElse(T t) :  如果调用对象包含值，返回该值，否则返回t
	 */
	@Test
	public void test3() {
		Optional<Person> op = Optional.empty();
		Person person = op.orElse(new Person("张三"));
		System.out.println(person);
	}

	/**
	 * orElseGet(Supplier s) :如果调用对象包含值，返回该值，否则返回 s 获取的值
	 */
	@Test
	public void test4() {
		//Optional<Person> op = Optional.ofNullable(new Person("张三"));
		Optional<Object> op = Optional.empty();
		System.out.println(op.orElseGet(() -> new Person()));
	}

	/**
	 * map(Function f): 如果有值对其处理，并返回处理后的Optional，否则返回 Optional.empty()
	 * flatMap(Function mapper):与 map 类似，要求返回值必须是Optional
	 */
	@Test
	public void test5() {
		Optional<Person> op = Optional.ofNullable(new Person(15, "青龙"));
		Optional<String> op2 = op.map(Person::getLastName);
		System.out.println(op2.get());
		
		Optional<Integer> op3 = op.flatMap(p -> Optional.ofNullable(p.getAge()) );
		System.out.println(op3.get());
		
	}

	@Test
	public void test_map() {
		A a = new A();
		// Optional 式写法， 获取嵌套对象中的属性值
		Optional.ofNullable(a)
				.map(A::getB)
				.map(B::getC)
				.map(C::getName)
				.ifPresent(System.out::println);

		// 原判断写法
		if (Objects.nonNull(a) && Objects.nonNull(a.getB()) && Objects.nonNull(a.getB().getC())
				&& StrUtil.isNotBlank(a.getB().getC().getName())) {
			System.out.printf(">>>>>>>>>> %s ", a.getB().getC().getName());
		}
	}
}

@Data
class A {
	private B b;
}

@Data
class B {
	private C c;
}

@Data
class C {
	private String name;
}